home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d3 / snip22.arc / SNIPPER.ASM < prev    next >
Assembly Source File  |  1990-01-24  |  29KB  |  859 lines

  1. page 60,132
  2. ; SNIPPER by Tom Kihlken
  3. ;
  4. ; Copyright (c)    1987 by    Ziff Communications Co.
  5. ; PC Magazine 1987:  Vol 6/No. 19, October 27, 1987 (Utilities)
  6. ;
  7. ; SNIPPER is a resident    utility    which allows cutting out a portion
  8. ; of the screen.  The selected portion may be printed, written
  9. ; to disk or entered in    the keyboard buffer.  Activate SNIPPER by
  10. ; pressing ALT-W, then position    the cursor in the upper    left corner of
  11. ; the window using the arrow keys.  Press CR to    fix the    first corner,
  12. ; then expand the window with arrow keys.  Finally, type "P" to    print,
  13. ; "F" for disk file, "G" to retrieve or    CR for a help menu.  Press ESC
  14. ; any time to exit SNIPPER.  When installing SNIPPER, use the optional
  15. ; parameters to    expand it's internal buffer for displays (such as the
  16. ; EGA) containing more than the    standard 25 rows and 80    columns.
  17. ;   SNIPPER  [rows,columns]
  18.  
  19. ; Version 1.0 -    as published.
  20. ; Version 1.1 -    corrects a bug in the INT 21 interrupt routine.
  21. ; Version 1.2 -    runs correctly on the AT&T 6300
  22. ; Version 2.0 -     6/22/88 allow "R" to go to Right Edge.    Jim Turner 71560,3452
  23. ; Version 2.1 -    10/30/88 suggestions from Tom K.    Jim Turner 71560,3452
  24. ; Version 2.2 -    01/25/90 Consolidated.            Tim Farley, Atlanta, GA
  25. ;           (Turner's revisions did not include all of Kihlken's
  26. ;           published fixes, and    he untabified the file).
  27. ;        Added support for Expanded 101/102 key keyboard.
  28. ;        Added scan code    to RETURN--some    programs check the scan
  29. ;           code, so it needs to    be there so RETURN will    be processed.
  30. ;        Moved patch locations to fixed spot at 17F and 18F.
  31. ;        Removed    call to    INT 16 *inside*    INT 9 (yikes!).
  32. ;        Made sure all changes since published version are notated.
  33. ;
  34.  
  35. ;------------------------------------;
  36. ; BIOS_SEG IS THE ROM-BIOS DATA    AREA ;
  37. ;------------------------------------;
  38. BIOS_SEG    SEGMENT    AT 0040H
  39.         ORG    0017H                           ;[TF]
  40. KB_FLAG        DB    ?        ;CURRENT SHIFT STATE           ;[TF]
  41.         ORG    004AH
  42. CRT_COLS    DB    ?        ;CURRENT NUMBER    OF COLUMNS
  43.         ORG    0050H
  44. CURSOR_POSN    DW    8 DUP(?)    ;CURRENT CURSOR    LOCATION
  45.         ORG    0062H
  46. ACTIVE_PAGE    DB    ?        ;ACTIVE    PAGE FOR CGA AND EGA
  47.         ORG    0084H
  48. BIOS_ROWS    DB    ?        ;LAST ROW NUMBER FOR EGA
  49. BIOS_SEG    ENDS
  50.  
  51. CSEG        SEGMENT
  52.         ASSUME    CS:CSEG,DS:NOTHING
  53.         ORG    0100H        ;BEGINNING FOR .COM PROGRAMS
  54. START:        JMP    INITIALIZE    ;INITIALIZATION    CODE IS    AT END
  55.  
  56. ;--------------------------------;
  57. ; DATA AREA USED BY THIS PROGRAM ;
  58. ;--------------------------------;
  59. COPYRIGHT    DB    "SNIPPER 2.2 (c) 1987 Ziff Communications Co."
  60.         DB    13,10,"PC Magazine ",254," Tom Kihlken"
  61.         DB    13,10,"Hotkey is ALT-W",13,10,"$",1AH
  62.         DB    17 DUP (0)    ;room to patch hot key name       ;[TF]
  63. ;
  64.         DB    "KEY SCAN CODE->"    ;alert snoops to patch       ;[TF]
  65. HOTKEY        DB    11H        ;SCAN CODE FOR "W" KEY           ;[TF]
  66.         DB    "SHIFT MASK---->"    ;alert snoops to patch       ;[TF]
  67. SHIFT_MASK    DB    00001000B    ;MASK FOR ALT KEY           ;[TF]
  68. ;
  69. INSTALLED_MSG    DB    "Already Installed",13,10,"$"
  70. BAD_DOS_MSG    DB    "Requires DOS 2.0+",13,10,"$"
  71. OLDINT09    DD    ?    ;OLD KEYBOARD BREAK INTERRUPT VECTOR
  72. OLDINT13    DD    ?    ;OLD BIOS DISK IO INTERRUPT VECTOR
  73. OLDINT16    DD    ?    ;OLD KEYBOARD INTERRUPT    VECTOR
  74. OLDINT21    DD    ?    ;OLD DOS FUNCTION INTERRUPT VECTOR
  75. ERR_STAT    DB    ?    ;ERROR STATUS DURING FILE OUTPUT
  76. FILE_PROMPT    DB    "Enter Filename: "
  77. FILENAME    DB    "SCREEN.CUT"    ;THE DEFAULT FILENAME
  78.         DB    15 DUP (0)    ;LEAVE ROOM FOR    DRIVE AND PATH
  79. BUFF_NEXT    DW    BUFF_START    ;POINTER TO NEXT KEY IN    BUFFER
  80. BUFF_LAST    DW    BUFF_START    ;POINTER TO LAST KEY IN    BUFFER
  81. BUFF_START    EQU    OFFSET INITIALIZE
  82. BUFF_SIZE    EQU    25*(80+2)    ;ROOM FOR 25 ROWS OF 80    COLUMNS
  83. BUFF_END    DW    BUFF_START+BUFF_SIZE
  84. TOP_LEFT    LABEL    WORD        ;FIRST CORNER OF WINDOW
  85. LEFT_SIDE    DB    0        ;COLUMN    NUMBER OF LEFT SIDE
  86. TOP_ROW        DB    0        ;ROW NUMBER OF TOP SIDE
  87. BOT_RIGHT    LABEL    WORD        ;SECOND    CORNER OF WINDOW
  88. RIGHT_SIDE    DB    ?        ;COLUMN    NUMBER OR RIGHT    SIDE
  89. BOT_ROW        DB    ?        ;ROW NUMBER OF BOTTOM
  90. SEND_CHAR    DW    ?        ;POINTER TO CHARACTER HANDLER
  91. SEND_KEYS    DB    0        ;IF=1, USE KEYSTROKES FROM BUFFER
  92. WRIT_FILE    DB    0        ;IF=1, NEED TO WRITE TO    DISK
  93. BUSY_FLAGS    DB    0        ;BIT MASKED AS FOLLOWS:
  94.                     ; 1 - DOS IS ACTIVE
  95.                     ; 2 - BIOS IO IS ACTIVE
  96.                     ; 4 - SNIPPER IS ACTIVE
  97. DOS_STAT    DB    0        ;CURRENT DOS FUNCTION
  98. SCRN_ROWS    DB    ?        ;REAL SCREEN ROWS           ;[TK]
  99. R_FLAG        DB    0        ;HAS THE USER PRESSED 'R'?       ;[JT]
  100.  
  101. HELP_MENU    DB    201,10 DUP(205),187
  102.         DB    186," F - File ",186
  103.         DB    186," P - Print",186
  104.         DB    186," S - Save ",186
  105.         DB    186," G - Get  ",186
  106.         DB    186,"Esc- Quit ",186
  107.         DB    200,10 DUP(205),188
  108.  
  109. ;------------------------------------------------------------------;
  110. ; SNIPPER BUILDS THE WINDOW AND    ACCEPTS    COMMANDS FROM THE KEYBOARD ;
  111. ;------------------------------------------------------------------;
  112. SNIPPER        PROC    NEAR
  113.         ASSUME    DS:CSEG, ES:BIOS_SEG
  114.  
  115.         MOV    SCRN_ROWS,24    ;DEFAULT NUMBER    OF ROWS           ;[TK]
  116.                                        ;[TK]
  117.         MOV    AH,12H                           ;[TK]
  118.         MOV    BL,10H        ;GET EGA INFO               ;[TK]
  119.         INT    10H                           ;[TK]
  120.         CMP    BL,10H        ;DID BL    CHANGE?               ;[TK]
  121.         JE    NOT_EGA        ;IF NO,    EGA IS NOT PRESENT       ;[TK]
  122.         TEST    BYTE PTR ES:[00087H],8 ;IS EGA ACTIVE?           ;[TK]
  123.         JNZ    NOT_EGA                           ;[TK]
  124.         MOV    AL,BIOS_ROWS                       ;[TK]
  125.         MOV    SCRN_ROWS,AL                       ;[TK]
  126. NOT_EGA:                                   ;[TK]
  127.         XOR    BX,BX        ;BX IS INCREMENT FOR ROW/COLUMN
  128. GET_KB_KEY1:
  129.         MOV    DX,TOP_LEFT    ;GET LOCATION OF FIRST CORNER
  130.         ADD    DH,BH        ;ADD IN    THE ROW    INCREMENT
  131.         ADD    DL,BL        ;ADD IN    THE COLUMN INCREMENT
  132.         CMP    DL,0        ;AT LEFT EDGE OF SCREEN?
  133.         JGE    NOT_LEFT_EDGE
  134.         MOV    DL,CRT_COLS    ;JUMP TO THE RIGHT EDGE
  135.         DEC    DL
  136. NOT_LEFT_EDGE:
  137.         CMP    DL,CRT_COLS    ;AT RIGHT EDGE OF SCREEN YET?
  138.         JB    NOT_RIGHT_EDGE    ;IF NOT, KEEP MOVING RIGHT
  139.         XOR    DL,DL        ;IF YES, WRAP TO LEFT EDGE
  140. NOT_RIGHT_EDGE:
  141.         CMP    DH,0        ;AT TOP    OF SCREEN YET?
  142.         JGE    NOT_AT_TOP
  143.         MOV    DH,SCRN_ROWS    ;JUMP DOWN TO THE BOTTOM       ;[TK]
  144. NOT_AT_TOP:
  145.         CMP    DH,SCRN_ROWS    ;AT BOTTOM OF SCREEN?           ;[TK]
  146.         JLE    NOT_AT_BOTTOM
  147.         XOR    DH,DH        ;JUMP BACK TO THE TOP
  148. NOT_AT_BOTTOM:
  149.         MOV    TOP_LEFT,DX    ;SAVE NEW CORNER LOCATION
  150.         CALL    REV_VIDEO    ;CHANGE    IT TO REVERSE VIDEO
  151.         XOR    AH,AH        ;BIOS KEYBOARD INPUT
  152.         INT    16H        ;GET A KEYSTROKE
  153.         PUSH    AX
  154.         CALL    REV_VIDEO    ;PUT ATTRIBUTE BACK TO NORMAL
  155.         POP    AX
  156.         CMP    AH,1        ;IS IT ESCAPE?
  157.         JNE    NOT_ESC
  158.         RET            ;JUST RETURN TO    EXIT
  159. NOT_ESC:
  160.         MOV    BX,0FF00H    ;INCREMENT TO SUBTRACT ONE ROW
  161.         CMP    AH,48H        ;IS IT UP ARROW?
  162.         JE    GET_KB_KEY1
  163.         MOV    BX,0100H    ;INCREMENT TO ADD ONE ROW
  164.         CMP    AH,50H        ;IS IT DOWN ARROW?
  165.         JE    GET_KB_KEY1
  166.         MOV    BX,0001H    ;INCREMENT TO ADD ONE COLUMN
  167.         CMP    AH,4DH        ;IS IT RIGHT ARROW?
  168.         JE    GET_KB_KEY1
  169.         MOV    BX,00FFH    ;INCREMENT TO SUBTRACT ONE COLUMN
  170.         CMP    AH,4BH        ;IS IT LEFT ARROW?
  171.         JE    GET_KB_KEY1
  172.         XOR    BX,BX
  173.         CMP    AL,13        ;IS IT A CARRIAGE RETURN?
  174.         JNE    NOT_CR
  175.         MOV    DX,TOP_LEFT    ;A CARRIAGE RETURN WAS PRESSED
  176.         MOV    BOT_RIGHT,DX    ;INITIALIZE THE    SECOND CORNER
  177.         CALL    REV_VIDEO    ;CHANGE    IT BACK    TO REVERSE VIDEO
  178.         JMP    SHORT GET_KB_KEY2
  179. NOT_CR:
  180.         CMP    AH,22H        ;IS IT THE "G" KEY
  181.         JE    TYPE_BUFF    ;IF YES, THAN GET THE WINDOW
  182.         JMP    GET_KB_KEY1    ;JUST GET ANOTHER KEY
  183. TYPE_BUFF:
  184.         MOV    SEND_KEYS,1    ;SIGNAL    TO SEND    THE KEYS
  185.         RET
  186. GET_KB_KEY2:
  187.         XOR    AH,AH
  188.         INT    16H        ;GET A KEYSTROKE
  189. GOT_KEY2:    MOV    DX,BOT_RIGHT
  190.         CMP    AH,13h        ;Is it "r" key?               ;[JT]
  191.         JE    GOT_R        ; Go to    Right edge           ;[JT]
  192.         MOV    R_FLAG,0    ;  else    clear that flag           ;[JT]
  193.         CMP    AH,48H        ;IS IT UP ARROW?
  194.         JE    SUB_ROW        ;SUBTRACT A ROW    FROM WINDOW
  195.         CMP    AH,50H        ;IS IT DOWN ARROW?
  196.         JE    ADD_ROW        ;ADD A ROW TO THE WINDOW
  197.         CMP    AH,4DH        ;IS IT RIGHT ARROW?
  198.         JE    ADD_COL        ;ADD A COLUMN TO THE WINDOW
  199.         CMP    AH,4BH        ;IS IT LEFT ARROW?
  200.         JE    SUB_COL        ;SUBTRACT A COLUMN FROM    WINDOW
  201.         JMP    NOT_ARROW_KEY
  202. SUB_COL:
  203.         DEC    DL        ;SUBTRACT A COLUMN
  204.         CMP    DL,LEFT_SIDE    ;DONT ERASE IT COMPLETELY
  205.         JL    GET_KB_KEY2
  206.         MOV    RIGHT_SIDE,DL    ;SAVE NEW RIGHT    SIDE COLUMN
  207.         INC    DL
  208.         JMP    SHORT COL_LOOP
  209.  
  210. GOT_R:        MOV    R_FLAG,1    ;"r"-key rec'd                      [JT]
  211.  
  212. ADD_COL:
  213.         MOV    DX,BOT_RIGHT    ;Tom's suggested fix of rev'd video [JT]
  214.         INC    DL        ;ADD A COLUMN
  215.         CMP    DL,CRT_COLS    ;AT RIGHT EDGE OF SCREEN?
  216.         JAE    GET_KB_KEY2    ;STOP WHEN SCREEN IS FILLED
  217.         MOV    RIGHT_SIDE,DL    ;SAVE NEW RIGHT    SIDE COLUMN
  218. COL_LOOP:
  219.         CALL    REV_VIDEO    ;REVERSE THIS CHARACTER
  220.         DEC    DH        ;MOVE TO NEXT ROW
  221.         CMP    DH,TOP_ROW    ;AT TOP    ROW YET?
  222.         JGE    COL_LOOP    ;LOOP UNTIL AT TOP ROW
  223.         CMP    R_FLAG,1    ;Are we    handling an "R"    now?        [JT]
  224.         JE    ADD_COL        ;Yup.  Go repeat movement till done [JT]
  225.         JMP    GET_KB_KEY2
  226. SUB_ROW:
  227.         DEC    DH
  228.         CMP    DH,TOP_ROW    ;AT TOP    OF WINDOW?
  229.         JL    GET_KB_KEY2    ;DONT ERASE IT COMPLETELY
  230.         MOV    BOT_ROW,DH
  231.         INC    DH
  232.         JMP    SHORT ROW_LOOP
  233. ADD_ROW:
  234.         INC    DH
  235.         CMP    DH,SCRN_ROWS    ;AT BOTTOM OF SCREEN?           ;[TK]
  236.         JG    GET_KB_KEY2    ;STOP WHEN SCREEN IS FILLED
  237.         MOV    BOT_ROW,DH
  238. ROW_LOOP:
  239.         CALL    REV_VIDEO    ;REVERSE THIS CHARACTER
  240.         DEC    DL        ;MOVE TO NEXT COLUMN
  241.         CMP    DL,LEFT_SIDE    ;AT LEFT EDGE YET?
  242.         JGE    ROW_LOOP    ;CONTINUE UNTIL    AT LEFT    EDGE
  243.         JMP    GET_KB_KEY2
  244. NOT_ARROW_KEY:
  245.         CMP    AH,19H        ;WAS IT    THE "P"    KEY?
  246.         JNE    NOT_P
  247.         MOV    SEND_CHAR,OFFSET PRINT_CHAR
  248.         JMP    READ_WINDOW
  249. NOT_P:
  250.         MOV    BUFF_NEXT,BUFF_START
  251.         MOV    BUFF_LAST,BUFF_START
  252.         MOV    SEND_CHAR,OFFSET BUFF_CHAR
  253.  
  254.         CMP    AH,1FH        ;WAS IT    THE "S"    KEY?
  255.         JNE    NOT_S
  256.         MOV    SEND_CHAR,OFFSET BUFF_CHAR
  257.         JMP    READ_WINDOW
  258. NOT_S:
  259.         CMP    AH,22H        ;IS IT THE "G" KEY
  260.         JNE    NOT_G
  261.         MOV    SEND_KEYS,1
  262.         JMP    READ_WINDOW
  263. NOT_G:
  264.         CMP    AH,21H        ;IS IT THE "F" KEY
  265.         JNE    NOT_F
  266.         MOV    WRIT_FILE,0
  267.         CALL    GET_FILENAME
  268.         CMP    WRIT_FILE,-1    ;WAS ESCAPE REQUESTED?
  269.         JE    ERASE_BOX
  270.         CALL    READ_WINDOW
  271.         MOV    WRIT_FILE,1
  272.         TEST    BUSY_FLAGS,00000011B    ;IS INT21 OR INT13 BUSY?
  273.         JNZ    RETURN        ;IF YES, WAIT TILL LATER
  274.         CALL    WRITE_TO_FILE    ;IF NOT, DO IT NOW
  275. RETURN:
  276.         RET
  277. NOT_F:
  278.         CMP    AH,1        ;IS IT ESCAPE?
  279.         JE    ERASE_BOX ;IF YES, ERASE BOX AND EXIT
  280.         CMP    AL,13        ;IS IT A CARRIAGE RETURN?
  281.         JE    DISPLAY_HELP    ;IF YES, DISPLAY HELP
  282.         JMP    GET_KB_KEY2    ;OTHERWISE JUST    GET ANOTHER KEY
  283. ERASE_BOX:
  284.         MOV    SEND_CHAR,OFFSET RETURN
  285.         JMP    READ_WINDOW
  286. DISPLAY_HELP:
  287.         CALL    EXCHANGE_HELP    ;PUT UP    THE HELP MENU
  288.         XOR    AH,AH
  289.         INT    16H        ;GET ANOTHER KEYSTROKE
  290.         PUSH    AX        ;SAVE THE KEYSTROKE
  291.         CALL    EXCHANGE_HELP    ;PULL DOWN THE HELP MENU
  292.         POP    AX        ;GET BACK THE KEYSTROKE
  293.         JMP    GOT_KEY2
  294. ;*********************************************************************
  295. REV_VIDEO:
  296.         CALL    READ_CHAR    ;READ CHARACTER    AND ATTRIBUTE
  297.         MOV    BL,AH        ;SAVE ATTRIBUTE    IN BL
  298.         AND    BL,10001000B    ;GET BLINK AND INTENSITY BITS
  299.         AND    AH,01110111B    ;NOW LOOK ONLY AT COLOR    BITS
  300.         MOV    CL,4        ;ROTATE    FOUR COUNTS
  301.         ROR    AH,CL        ;ROTATE    FOREGROUND AND BACKGROUND
  302.         OR    BL,AH        ;PUT BACK BLINK    AND INTENSITY BITS
  303.         CALL    DISPLAY_CHAR    ;WRITE CHARACTER AND ATTRIBUTE
  304.         RET
  305. ;*********************************************************************
  306. READ_WINDOW:
  307.         MOV    DX,TOP_LEFT    ;GET LOCATION OF FIRST CORNER
  308. READ_LOOP:
  309.         CALL    REV_VIDEO    ;PUT ATTRIBUTE BACK TO NORMAL
  310.         CALL    READ_CHAR    ;READ THE CHARACTER
  311.         CALL    SEND_CHAR    ;CALL TO THE POINTER
  312.         INC    DL        ;NEXT CHAR IN ROW
  313.         CMP    DL,RIGHT_SIDE    ;AT THE    RIGHT BORDER YET?
  314.         JLE    READ_LOOP    ;DO ALL    CHARACTERS IN THIS ROW
  315.         CALL    CR_LF        ;SEND CR-LF AFTER EACH ROW
  316.         INC    DH        ;MOVE TO NEXT ROW
  317.         MOV    DL,LEFT_SIDE    ;BACK TO LEFT EDGE
  318.         CMP    DH,BOT_ROW    ;AT THE    BOTTOM BORDER YET?
  319.         JLE    READ_LOOP    ;READ ENTIRE WINDOW
  320.         RET
  321. ;*********************************************************************
  322. CR_LF:
  323.         MOV    AL,13
  324.         CALL    SEND_CHAR    ;SEND A    CARRIAGE RETURN
  325.         MOV    AL,10
  326.         CALL    SEND_CHAR    ;SEND A    LINE FEED
  327.         RET
  328. ;*********************************************************************
  329. DISPLAY_CHAR:
  330.         PUSH    BX        ;SAVE THE ATTRIBUTE
  331.         CALL    GET_CURS_ADDR    ;GET ADDRESS OF    BIOS CURSOR
  332.         MOV    ES:[BX],DX    ;TELL BIOS WHERE THE CURSOR IS
  333.         POP    BX        ;GET BACK THE ATTRIBUTE
  334.         MOV    BH,ACTIVE_PAGE    ;GET ACTIVE PAGE
  335.         PUSH    CX        ;SAVE THE LOOP COUNT
  336.         MOV    CX,1        ;WRITE 1 CHARACTER
  337.         MOV    AH,9        ;WRITE CHARACTER AND ATTRIBUTE
  338.         INT    10H
  339.         POP    CX        ;RECOVER LOOP COUNT
  340.         RET            ;DONE WRITING THE CHARACTER
  341. ;*********************************************************************
  342. READ_CHAR:
  343.         CALL    GET_CURS_ADDR    ;GET ADDRESS OF    BIOS CURSOR
  344.         MOV    ES:[BX],DX    ;TELL BIOS WHERE THE CURSOR IS
  345.         MOV    BH,ACTIVE_PAGE    ;GET ACTIVE PAGE
  346.         MOV    AH,8        ;BIOS FUNCTION TO READ CHARACTER
  347.         INT    10H        ;READ THE CHARACTER/ATTRIBUTE
  348.         RET
  349. ;*********************************************************************
  350. PRINT_CHAR:
  351.         PUSH    DX
  352.         XOR    AH,AH        ;USE FUNCTION 0
  353.         XOR    DX,DX        ;PRINTER NUMBER    0
  354.         INT    17H        ;BIOS PRINT CHARACTER FUNCTION
  355.         ROR    AH,1        ;LOOK AT BIT ZERO
  356.         JNC    PRINT_OK    ;DID A TIMEOUT OCCUR?
  357.         MOV    SEND_CHAR,OFFSET RETURN
  358. PRINT_OK:
  359.         POP    DX
  360.         RET            ;DONE PRINTING CHARACTER
  361. ;*********************************************************************
  362. BUFF_CHAR:
  363.         MOV    BX,BUFF_LAST    ;GET LOCATION OF LAST CHARACTER
  364.         MOV    [BX],AL        ;PUT THE CHARACTER IN BUFFER
  365.         INC    BX        ;ADVANCE THE POINTER
  366.         MOV    BUFF_LAST,BX    ;CHECK FOR BUFFER FULL
  367.         CMP    BX,BUFF_END    ;IS THE    BUFFER FULL YET?
  368.         JNE    BUFF_OK        ;IF NOT, KEEP GOING
  369.         MOV    SEND_CHAR,OFFSET RETURN
  370. BUFF_OK:
  371.         RET            ;NOW ITS IN THE    BUFFER
  372. ;*********************************************************************
  373. GET_CURS_ADDR:
  374.         MOV    BL,ACTIVE_PAGE    ;GET THE CURRENT PAGE NUMBER
  375.         XOR    BH,BH        ;CONVERT TO A WORD OFFSET
  376.         SHL    BX,1        ;TIMES TWO FOR A WORD
  377.         ADD    BX,OFFSET CURSOR_POSN ;ADD IN BASE ADDRESS
  378.         RET
  379. ;*********************************************************************
  380. EXCHANGE_HELP:
  381.         XOR    DX,DX        ;START AT TOP LEFT CORNER
  382.         LEA    SI,HELP_MENU
  383. EXCHANGE_LOOP:
  384.         CMP    DL,12        ;AT LAST COLUMN    IN THIS    ROW YET?
  385.         JL    SWAP_CHAR
  386.         XOR    DL,DL        ;BACK TO FIRST COLUMN
  387.         INC    DH        ;DO THE    NEXT ROW
  388.         CMP    DH,7        ;AT LAST ROW YET?
  389.         JL    SWAP_CHAR    ;QUIT WHEN LAST    ROW IS DONE
  390.         RET
  391. SWAP_CHAR:
  392.         CALL    READ_CHAR    ;READ CHARACTER    AT THIS    POSITION
  393.         XCHG    AL,CS:[SI]    ;SWAP WITH THE HELP TEXT
  394.         MOV    BL,AH        ;ATTRIBUTE IS THE SAME
  395.         CALL    DISPLAY_CHAR    ;PUT NEW CHARACTER ON SCREEN
  396.         INC    DL        ;POINT TO NEXT POSITION
  397.         INC    SI
  398.         JMP EXCHANGE_LOOP
  399. ;*********************************************************************
  400. GET_FILENAME:
  401.         LEA    SI,FILE_PROMPT    ;POINT TO THE PROMPT FOR SOURCE
  402.         XOR    DI,DI        ;USE THE PSP FOR BUFFER
  403.         XOR    DX,DX        ;PUT PROMPT AT TOP LEFT    CORNER
  404.         MOV    CX,40        ;USE MAX OF 40 CHARACTERS
  405. DISPLAY_PROMPT:
  406.         PUSH    CX        ;SAVE LOOP COUNT
  407.         CALL    READ_CHAR    ;GET CHARACTER ON THIS LINE
  408.         MOV    CS:[DI],AX    ;STORE IT IN THE PSP
  409.         INC    DI        ;ADD TWO FOR NEXT CHARACTER
  410.         INC    DI
  411.         MOV    AL,CS:[SI]    ;GET NEXT PROMPT CHARACTER
  412.         INC    SI        ;NEXT CHARACTER    IN PROMPT
  413.         MOV    BL,47H        ;ATTRIBUTE FOR PROMPT
  414.         CALL    DISPLAY_CHAR    ;PUT UP    THE PROMPT CHARACTER
  415.         INC    DL        ;POINT TO NEXT COLUMN
  416.         POP    CX        ;GET BACK LOOP COUNT
  417.         LOOP    DISPLAY_PROMPT    ;ENTIRE    PROMPT AND FILENAME
  418. FIND_LAST_LETTER:
  419.         DEC    SI        ;BACKUP    TO LAST    LETTER
  420.         DEC    DL        ;BACKUP    TO LAST    COLUMN
  421.         CMP    BYTE PTR [SI],0    ;IS THIS A LETTER?
  422.         JE    FIND_LAST_LETTER;BACKUP    UNTILL A LETTER    IS FOUND
  423.         INC    DL        ;PUT BLINKING BOX AT LAST LETTER
  424. READ_KB:
  425.         MOV    AL,219        ;ASCII FOR BOX CHARACTER
  426.         MOV    BL,47H+80H    ;MAKE IT A BLINKING BOX    CHARACTER
  427.         CALL    DISPLAY_CHAR    ;WRITE THE BLINKING BOX
  428. ;
  429.         XOR    AH,AH        ;FUNCTIO 0 TO GET NEXT KEY
  430.         INT    16H        ;BIOS KEYBOARD INPUT
  431.         CMP    AL,13        ;IS IT A CARRIAGE RETURN?
  432.         JE    ERASE_PROMPT
  433.         CMP    AL,8        ;IS IT A BACKSPACE?
  434.         JE    BACK_SPACE
  435.         CMP    AH,1        ;IS IT ESCAPE?
  436.         JE    ESC_RET
  437.         CMP    AL,"."        ;IS IT A VALID LETTER?
  438.         JL    READ_KB
  439.         CMP    AL,"z"        ;IS IT A VALID LETTER?
  440.         JG    READ_KB
  441.         CMP    DL,39        ;ONLY ALLOW 40 CHARACTERS
  442.         JGE    READ_KB
  443. TTY_KEY:
  444.         MOV    BL,47H        ;ATTRIBUTE FOR FILENAME
  445.         CALL    DISPLAY_CHAR    ;WRITE THE LETTER
  446.         INC    DL        ;MOVE TO NEXT COLUMN
  447.         JMP    READ_KB        ;GET ANOTHER KEYSTROKE
  448. BACK_SPACE:
  449.         CMP    DL,16        ;AT BEGINNING OF LINE?
  450.         JLE    READ_KB        ;IF YES, CAN'T BACKUP FROM HERE
  451.         MOV    AL,0        ;WRITE A NORMAL    BLANK (ASCII 0)
  452.         MOV    BL,47H        ;ATTRIBUTE FOR FILENAME
  453.         CALL    DISPLAY_CHAR    ;WRITE THE LETTER
  454.         DEC    DL        ;BACKUP    THE CURSOR
  455.         JMP    READ_KB        ;THEN GET THE NEXT KEY
  456. ESC_RET:
  457.         MOV    WRIT_FILE,-1    ;INDICATE ESCAPE IS REQUESTED
  458. ERASE_PROMPT:
  459.         XOR    AL,AL        ;GET RID OF THE    CURSOR
  460.         CALL    DISPLAY_CHAR    ;WRITE THE LETTER
  461.         LEA    DI,FILE_PROMPT    ;COPY TO FILENAME
  462.         XOR    SI,SI        ;COPY FROM PSP
  463.         XOR    DX,DX        ;PROMPT    IS AT ROW ZERO
  464.         MOV    CX,40        ;COPY ALL 40 CHARACTERS
  465. ERASE_LOOP:
  466.         CALL    READ_CHAR    ;GET CHARACTER ON THIS LINE
  467.         MOV    CS:[DI],AL    ;PUT IN    BACK IN    MEMORY
  468.         INC    DI
  469.         MOV    AX,CS:[SI]    ;GET THE ORIGINAL CHARACTER BACK
  470.         MOV    BL,AH        ;PUT ATTRIBUTE INTO BL
  471.         INC    SI
  472.         INC    SI
  473.         CALL    DISPLAY_CHAR    ;WRITE ORIGINAL    CHARACTER
  474.         INC    DL        ;MOVE TO NEXT COLUMN
  475.         LOOP    ERASE_LOOP    ;ERASE THE ENTIRE PROMPT
  476.         RET
  477. SNIPPER        ENDP
  478.  
  479. ;---------------------------------------------------------------------;
  480. ; THIS COPIES THE BUFFER CONTENTS TO A FILE. IT    SHOULD ONLY BE CALLED ;
  481. ; WHEN DOS IS IN A STABLE AND REENTRANT    CONDITION.              ;
  482. ;---------------------------------------------------------------------;
  483. WRITE_TO_FILE    PROC    NEAR
  484.         ASSUME    DS:NOTHING, ES:NOTHING
  485.  
  486.         MOV    WRIT_FILE,0    ;TURN OFF REQUEST FLAG
  487.         PUSH    AX        ;MUST PRESERVE ALL REGISTERS
  488.         PUSH    BX
  489.         PUSH    CX
  490.         PUSH    DX
  491.         PUSH    DS
  492.         PUSH    ES
  493.         PUSH    CS
  494.         POP    DS
  495.         ASSUME    DS:CSEG        ;DS POINTS TO OUR CODE SEGMENT
  496.         MOV    AX,3524H    ;GET DOS CRITICAL ERROR    VECTOR
  497.         INT    21H        ;DOS FUNCTION TO GET VECTOR
  498.         PUSH    BX        ;SAVE OLD VECTOR ON STACK
  499.         PUSH    ES
  500.  
  501. ; REPLACE THE DOS SEVERE ERROR INTERRUPT WITH OUR OWN ROUTINE.
  502.  
  503.         MOV    DX,OFFSET NEWINT24
  504.         MOV    AX,2524H    ;SETUP TO CHANGE INT 24h VECTOR
  505.         INT    21H        ;CHANGE    DOS SEVERE ERROR VECTOR
  506.         MOV    DX,OFFSET FILENAME ;POINT TO FILENAME
  507.  
  508. ; FIRST    TRY TO OPEN THE    FILE.  IF DOS RETURNS WITH THE CARRY FLAG SET,
  509. ; THE FILE DIDN'T EXIST AND WE MUST CREATE IT.  ONCE THE FILE IS OPENED,
  510. ; ADVANCE THE FILE POINTER TO THE END OF FILE TO APPEND.
  511.  
  512.         MOV    AX,3D02H    ;DOS FUNCTION TO OPEN FILE
  513.         INT    21H        ;DOS WILL RETURN WITH CARRY FLAG
  514.         JC    FILE_NOT_FOUND    ;SET IF    FILE DOESN'T EXIST.
  515.         MOV    BX,AX        ;KEEP HANDLE IN    BX ALSO
  516.         XOR    CX,CX        ;MOVE DOS FILE POINTER TO THE
  517.         XOR    DX,DX        ;END OF    THE FILE. THIS LETS US
  518.         MOV    AX,4202H    ;APPEND    THIS TO    AN EXISTING FILE
  519.         INT    21H        ;DOS FUNCTION TO MOVE POINTER
  520.         JNC    WRITE_FILE    ;IF NO ERROR, CONTINUE TO WRITE
  521. DOS_ERROR:
  522.         CMP    ERR_STAT,0    ;DID A SEVERE ERROR OCCUR?
  523.         JNE    REP_VECTOR    ;IF SEVERE ERROR, JUST QUIT
  524.         JMP    SHORT CLOSE_FILE;JUST CLOSE THE    FILE
  525.  
  526. FILE_NOT_FOUND:    CMP    ERR_STAT,0    ;DID A SEVERE ERROR OCCUR?
  527.         JNE    REP_VECTOR    ;IF SEVERE ERROR, JUST QUIT
  528.         MOV    CX,0020H    ;ATTRIBUTE FOR NEW FILE
  529.         MOV    AH,3CH        ;CREATE    FILE FOR WRITING
  530.         INT    21H        ;DOS FUNCTION TO CREATE    FILE
  531.         JC    DOS_ERROR    ;ON ANY    ERROR, TAKE JUMP
  532.         MOV    BX,AX        ;SAVE HANDLE IN    BX
  533. WRITE_FILE:    MOV    DX,BUFF_START    ;POINT TO BUFFER
  534.         MOV    CX,BUFF_LAST    ;GET BUFFER POINTER
  535.         SUB    CX,DX        ;NUMBER    OF CHARS IN BUFFER
  536.         MOV    AH,40H        ;DOS WRITE TO A    DEVICE FUNCTION
  537.         INT    21H        ;WRITE TO THE FILE
  538. CLOSE_FILE:
  539.         MOV    AH,3EH        ;DOS FUNCTION TO CLOSE THE FILE
  540.         INT    21H
  541. REP_VECTOR:
  542.         POP    DS        ;GET INT 24H VECTOR FROM STACK
  543.         POP    DX
  544.         MOV    AX,2524H    ;RESTORE CRITICAL ERROR    VECTOR
  545.         INT    21H        ;DOS FUNCTION TO CHANGE    VECTOR
  546.         POP    ES        ;FINALLY RESTORE ALL REGISTERS
  547.         POP    DS
  548.         POP    DX
  549.         POP    CX
  550.         POP    BX
  551.         POP    AX
  552.         RET            ;FINISHED WRITING TO DISK
  553. WRITE_TO_FILE    ENDP
  554. ;---------------------------------------------------------------------;
  555. ; INTERRUPT 09 ROUTINE.     WATCH FOR TRIGGER KEY TO POP UP.
  556. ;---------------------------------------------------------------------;
  557. NEWINT09    PROC    FAR
  558.         ASSUME    DS:NOTHING, ES:NOTHING
  559.         STI            ;ALLOW OTHER INTERRUPTS
  560.         PUSH    AX        ;MUST SAVE PROCESSOR STATE
  561.         IN    AL,60H        ;GET THE SCAN CODE
  562.         CMP    AL,BYTE    PTR CS:[HOTKEY]          ;IS IT THE HOT KEY?  ;[TF]
  563.         JE    TRIGGER        ;IF YES, CHECK THE MASK
  564. INT09_EXIT:    POP    AX        ;RESTORE THE PROCESSOR STATE
  565.         JMP    OLDINT09    ;CONTINUE WITH ROM ROUTINE
  566.  
  567. TRIGGER:
  568.         PUSH    DS                           ;[TF]
  569.         MOV    AX,BIOS_SEG    ;ES POINTS TO BIOS DATA    AREA       ;[TF]
  570.         MOV    DS,AX                           ;[TF]
  571.         ASSUME    DS:BIOS_SEG                       ;[TF]
  572.         MOV    AL,KB_FLAG    ;GET KEYBOARD STATUS FROM BIOS       ;[TF]
  573.         POP    DS                           ;[TF]
  574.         ASSUME    DS:NOTHING                       ;[TF]
  575.  
  576.         AND    AL,0FH        ;Take lower four bits
  577.         CMP    AL,BYTE    PTR CS:[SHIFT_MASK]   ;IS ALT KEY DOWN?       ;[TF]
  578.         JNZ    INT09_EXIT    ;IF NOT, IGNORE    IT
  579.         TEST    BUSY_FLAGS,00000100B ;IS SNIPPER ALREADY ACTIVE?
  580.         JNZ    INT09_EXIT    ;IF ACTIVE, THEN EXIT
  581.         OR    BUSY_FLAGS,00000100B ;ITS ACTIVE NOW
  582.         PUSHF
  583.         CALL    OLDINT09    ;LET ROM PROCESS THE KEY
  584.         PUSH    BX        ;MUST PRESERVE ALL REGISTERS
  585.         PUSH    CX
  586.         PUSH    DX
  587.         PUSH    BP
  588.         PUSH    SI
  589.         PUSH    DI
  590.         PUSH    DS
  591.         PUSH    ES
  592.         PUSH    CS
  593.         POP    DS        ;SET DS    TO CSEG
  594.  
  595.         MOV    AX,BIOS_SEG    ;ES POINTS TO BIOS DATA    AREA
  596.         MOV    ES,AX
  597.         ASSUME    DS:CSEG, ES:BIOS_SEG
  598.  
  599.         CALL    GET_CURS_ADDR    ;CURSOR    ADDRESS    FOR THIS PAGE
  600.         PUSH    ES:[BX]        ;SAVE CURSOR POSITION
  601.         CALL    SNIPPER        ;DO THE    WINDOW
  602.         CALL    GET_CURS_ADDR    ;CURS0R    ADDRESS    FOR THIS PAGE
  603.         POP    ES:[BX]        ;GET BACK CURSOR  POSITION
  604.         AND    BUSY_FLAGS,11111011B  ;SNIPPER IS NOT ACTIVE
  605.  
  606.         POP    ES        ;RESTORE ALL REGISTERS
  607.         POP    DS
  608.         POP    DI
  609.         POP    SI
  610.         POP    BP
  611.         POP    DX
  612.         POP    CX
  613.         POP    BX
  614.         POP    AX
  615.         IRET            ;NOW WERE ALL DONE
  616. NEWINT09    ENDP
  617. ;---------------------------------------------------------------------;
  618. ; INTERRUPT 13 ROUTINE.    SET BIOS BUST BIT                  ;
  619. ;---------------------------------------------------------------------;
  620. NEWINT13    PROC    FAR
  621.         ASSUME    DS:NOTHING, ES:NOTHING
  622.  
  623.         OR    BUSY_FLAGS,00000010B    ;SET BIOS BUSY BIT
  624.         PUSHF
  625.         CALL    OLDINT13    ;DO THE    BIOS FUNCTION
  626.         PUSHF            ;SAVE RESULT FLAGS
  627.         AND    BUSY_FLAGS,11111101B    ;CLEAR BIOS BUSY BIT
  628.         POPF            ;GET BACK RESULT FLAGS
  629.         STI            ;MUST RETURN WITH INTERUPTS ON
  630.         RET    2        ;RETURN    BIOS RESULT FLAGS
  631.  
  632. NEWINT13    ENDP
  633. ;---------------------------------------------------------------------;
  634. ; INTERRUPT 16 ROUTINE.    INSERT KEYSTROKES FROM BUFFER              ;
  635. ;---------------------------------------------------------------------;
  636. NEWINT16    PROC    FAR
  637.         ASSUME    DS:NOTHING, ES:NOTHING
  638.         PUSH    BX
  639.         CMP    SEND_KEYS,1    ;SENDING KEYS FROM BUFFER?
  640.         JE    INSERT_KEY    ;IF YES, THEN GET NEXT ONE
  641.         CMP    WRIT_FILE,1    ;ANYTHING TO WRITE TO DISK?
  642.         JE    CHECK_DOS_STAT    ;IF YES, THIS IS THE TIME
  643. BIOS_KB:
  644.         POP    BX
  645.         JMP    OLDINT16    ;JUST DO NORMAL    KB ROUTINE
  646. CHECK_DOS_STAT:
  647.         CMP    DOS_STAT,0AH    ;DOING READ STRING?
  648.         JE    BEGIN_NOW    ;IF YES, ITS SAFE TO BEGIN
  649.         CMP    DOS_STAT,8    ;DOING KEYBOARD    INPUT?
  650.         JNE    BIOS_KB        ;IF YES, ITS SAFE TO BEGIN
  651. BEGIN_NOW:
  652.         STI            ;GET INTERRUPTS    BACK ON
  653.         CALL    WRITE_TO_FILE    ;EMPTY THE BUFFER
  654.         JMP    BIOS_KB        ;CONTINUE WITH BIOS ROUTINE
  655. INSERT_KEY:
  656.         STI            ;INTERRUPTS BACK ON
  657.         MOV    BX,BUFF_NEXT    ;GET ADDRESS OF    NEXT BYTE
  658.         CMP    BX,BUFF_LAST    ;AT END    OF BUFFER YET?
  659.         JL    GET_A_KEY    ;IF NOT, GET THE NEXT ONE
  660.         MOV    SEND_KEYS,0    ;WHEN DONE, TURN OFF SEND SWITCH
  661. GET_A_KEY:
  662.         MOV    AL,CS:[BX]    ;GET THE NEXT KEY CODE
  663.         CMP    AL,10        ;IS IT A LINE FEED?
  664.         JNE    NOT_LF        ;DONT RETURN THE LINE FEEDS
  665.         INC    BUFF_NEXT    ;SKIP TO NEXT KEY
  666.         JMP    INSERT_KEY
  667. NOT_LF:
  668.         CMP    AH,1        ;REQUEST FOR STATUS ONLY?
  669.         JE    RETURN_STATUS    ;IF YES, RETURN    STATUS ONLY
  670.         CMP    AH,11H        ;Request for ENHANCED status?       ;[TF]
  671.         JE    RETURN_STATUS    ;If yes, return    that status       ;[TF]
  672.         CMP    AH,0        ;REQUEST TO GET    THE NEXT KEY
  673.         JE    RETURN_KEY    ;If yes, return    that key       ;[TF]
  674.         CMP    AH,10H        ;Get key on ENHANCED keyboard?       ;[TF]
  675.         JNE    BIOS_KB        ;IF NOT, IGNORE    THIS FUNCTION
  676. RETURN_KEY:                                   ;[TF]
  677.         INC    BX        ;REMOVE    THIS KEY FROM OUR BUFFER
  678.         MOV    BUFF_NEXT,BX    ;SAVE THE POINTER TO NEXT KEY
  679. RETURN_STATUS:
  680.         CMP    AL,0DH        ;Is this a Carriage Return?       ;[TF]
  681.         JNE    NEXT_KEY1    ;Nope, just pass it.           ;[TF]
  682.         MOV    AH,01CH        ;Put in    proper scan code for CR       ;[TF]
  683.         JMP    NEXT_KEY2    ;And send it               ;[TF]
  684. NEXT_KEY1:                                   ;[TF]
  685.         XOR    AH,AH        ;Scan code of zero           ;[TF]
  686. NEXT_KEY2:
  687.         OR    BL,1        ;CLEAR ZERO FLAG TO INDICATE A
  688.         POP    BX        ;KEY IS    AVAILIABLE
  689.         RET    2        ;RETURN    WITH THESE FLAGS
  690. NEWINT16    ENDP
  691. ;---------------------------------------------------------------------;
  692. ; INTERRUPT 21 ROUTINE.     THIS ROUTINE IS USED TO MONITOR DOS FUNCTION ;
  693. ; CALLS. IF THE    BUFFER NEEDS TO    BE FLUSHED, IT WIL BE DONE HERE.      ;
  694. ;---------------------------------------------------------------------;
  695. NEWINT21    PROC    FAR
  696.         ASSUME    DS:NOTHING, ES:NOTHING
  697.  
  698.         PUSHF            ;SAVE ENTRY FLAGS           ;[TK]
  699.  
  700.         STI            ;ALLOW INTERRUPTS
  701.         CMP    AH,4BH        ;IF EXEC               ;[TK]
  702.         JNE    NOT_EXEC                       ;[TK]
  703.         POPF                               ;[TK]
  704.         JMP    CS:OLDINT21    ;GO DIRECT               ;[TK]
  705. NOT_EXEC:
  706.         OR    AH,AH        ;DOING FUNCTION    ZERO?
  707.         JNE    NOT_ZERO
  708.         MOV    AH,4CH        ;IF YES, CHANGE    IT TO A    4CH
  709. NOT_ZERO:
  710.         OR    BUSY_FLAGS,00000001B    ;SET DOS BUSY BIT
  711.         MOV    DOS_STAT,AH
  712.         POPF            ;RESTORE ORIGINAL FLAGS           ;[TK]
  713.         PUSHF            ;SIMULATE AN INTERRUPT
  714.         CALL    CS:OLDINT21    ;DO THE    DOS FUNCTION
  715.         PUSHF            ;SAVE THE RESULT FLAGS
  716.         AND    BUSY_FLAGS,11111110B    ;CLEAR DOS BUSY    BIT
  717.         CMP    WRIT_FILE,1    ;ANYTHING TO WRITE TO DISK?
  718.         JNE    NO_WRITE    ;IF NOT    JUST RETURN
  719.         CALL    WRITE_TO_FILE    ;SAFE TO ACCESS    DISK NOW
  720. NO_WRITE:
  721.         POPF            ;RECOVER DOS RESULT FLAGS       ;[TK]
  722.         STI                               ;[TK]
  723.         RET    2        ;RETURN    WITH DOS RESULT    FLAGS
  724. NEWINT21    ENDP
  725.  
  726. ;---------------------------------------------------------------------;
  727. ; NEW INTERRUPT    24H (CRITICAL DOS ERROR).  THIS    INTERRUPT IS ONLY IN  ;
  728. ; EFFECT ONLY DURING A WRITE SCREEN.  IT IS REQUIRED TO    SUPPRESS THE  ;
  729. ; 'ABORT, RETRY, IGNORE' MESSAGE.  ALL FATAL DISK ERRORS ARE IGNORED. ;
  730. ;---------------------------------------------------------------------;
  731. NEWINT24    PROC    FAR
  732.         ASSUME    CS:CSEG, DS:NOTHING, ES:NOTHING
  733.         STI            ;TURN INTERRUPTS BACK ON
  734.         INC    ERR_STAT    ;SET THE ERROR FLAG
  735.         XOR    AL,AL        ;TELLS DOS TO IGNORE THE ERROR
  736.         IRET            ;THATS ALL WE DO HERE
  737. NEWINT24    ENDP
  738.  
  739. ;--------------------------------------------------------------------;
  740. ; HERE IS THE CODE USED    TO INITIALIZE SNIPPER.                 ;
  741. ;--------------------------------------------------------------------;
  742.         ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  743. INITIALIZE:
  744.         LEA    DX,COPYRIGHT
  745.         MOV    AH,9        ;DOS DISPLAY STRING SERVICE
  746.         INT    21H        ;DISPLAY TITLE MESSAGE
  747. ; SEARCH FOR AN    PREVIOUSLY INSTALLED COPY OF SNIPPER
  748.         NOT    BYTE PTR START    ;MODIFY    TO AVOID FASLE MATCH
  749.         XOR    BX,BX        ;START SEARCH AT SEGMENT ZERO
  750.         MOV    AX,CS        ;COMPARE TO THIS CODE SEGMENT
  751. NEXT_SEGMENT:
  752.         INC    BX        ;LOOK AT NEXT SEGMENT
  753.         CMP    AX,BX        ;UNTIL REACHING    THIS CODE SEG
  754.         MOV    ES,BX
  755.         JE    NOT_INSTALLED
  756.         LEA    SI,START    ;SETUP TO COMPARE STRINGS
  757.         MOV    DI,SI
  758.         MOV    CX,16        ;16 BYTES MUST MATCH
  759.         REP    CMPSB        ;COMPARE DS:SI TO ES:DI
  760.         OR    CX,CX        ;DID THE STRINGS MATCH?
  761.         JNZ    NEXT_SEGMENT    ;IF NO MATCH, TRY NEXT SEGMENT
  762.         LEA    DX,INSTALLED_MSG
  763.         JMP    SHORT ERR_EXIT
  764. NOT_INSTALLED:
  765.         MOV    AH,30H
  766.         INT    21H        ;GET DOS VERSION NUMBER
  767.         CMP    AL,2        ;IS IT HIGHER THAN 2.0?
  768.         JAE    VER_OK        ;IF YES, PROCEED
  769.         LEA    DX,BAD_DOS_MSG
  770. ERR_EXIT:    MOV    AH,9        ;DOS DISPLAY STRING SERVICE
  771.         INT    21H        ;DISPLAY ERRER MESSAGE
  772.         RET            ;RETURN    TO DOS
  773. VER_OK:
  774.         INC    SI        ;POINT TO FIRST    PARAMETER
  775.         MOV    SI,81H        ;POINT TO PARAMETER AREA
  776.         CALL    GET_PARAM    ;GET FIRST PARAMETER (ROWS)
  777.         PUSH    AX        ;SAVE THE ROW COUNT
  778.         CALL    GET_PARAM    ;GET SECOND PARAMETER (COLUMNS)
  779.         ADD    AX,2        ;ADD SPACE FOR CR AND LF
  780.         POP    BX        ;GET BACK FIRST    PARAMETER
  781.         MUL    BX        ;PRODUCT OF ROWS AND COLUMNS
  782.         OR    AX,AX        ;WAS ANYTHING ENTERED?
  783.         JZ    NO_PARAMS    ;IF NOT, USE DEFAULT VALUE
  784.         CMP    AX,10000    ;MAXIMUM BUFFER    IS 10000 BYTES
  785.         JLE    SIZE_IS_OK
  786.         MOV    AX,10000
  787. SIZE_IS_OK:
  788.         ADD    AX,BUFF_START
  789.         MOV    BUFF_END,AX    ;SET THE NEW BUFFER SIZE
  790. NO_PARAMS:
  791. ;
  792. ; EGA check here was removed & code was    added to popup routine (1.2)        ;[TK]
  793. ;
  794.         ASSUME    ES:NOTHING
  795.         MOV    AX,3509H    ;GET KEYBOARD BREAK VECTOR
  796.         INT    21H
  797.         MOV    WORD PTR [OLDINT09],  BX  ;SAVE    SEGMENT
  798.         MOV    WORD PTR [OLDINT09+2],ES  ;SAVE    OFFSET
  799.         MOV    DX, OFFSET NEWINT09
  800.         MOV    AX, 2509H
  801.         INT    21H        ;DOS FUNCTION TO CHANGE    VECTOR
  802.  
  803.         MOV    AX,3513H    ;GET BIOS DISK INTERRUPT VECTOR
  804.         INT    21H
  805.         MOV    WORD PTR [OLDINT13],  BX  ;SAVE    SEGMENT
  806.         MOV    WORD PTR [OLDINT13+2],ES  ;SAVE    OFFSET
  807.         MOV    DX, OFFSET NEWINT13
  808.         MOV    AX, 2513H
  809.         INT    21H        ;DOS FUNCTION TO CHANGE    VECTOR
  810.  
  811.         MOV    AX,3516H    ;GET KEYBOARD INPUT VECTOR
  812.         INT    21H
  813.         MOV    WORD PTR [OLDINT16],  BX  ;SAVE    SEGMENT
  814.         MOV    WORD PTR [OLDINT16+2],ES  ;SAVE    OFFSET
  815.         MOV    DX, OFFSET NEWINT16
  816.         MOV    AX, 2516H
  817.         INT    21H        ;DOS FUNCTION TO CHANGE    VECTOR
  818.  
  819.         MOV    AX,3521H    ;GET DOS FUNCTION VECTOR
  820.         INT    21H
  821.         MOV    WORD PTR [OLDINT21],  BX
  822.         MOV    WORD PTR [OLDINT21+2],ES
  823.         MOV    DX, OFFSET NEWINT21
  824.         MOV    AX, 2521H
  825.         INT    21H        ;DOS FUNCTION TO CHANGE    VECTOR
  826.  
  827. ;--------------------------------------------------------------------;
  828. ; DEALLOCATE OUR COPY OF THE ENVIORNMENT.                 ;
  829. ; EXIT USING INT 27H. LEAVE CODE AND SPACE FOR BUFFER RESIDENT.         ;
  830. ;--------------------------------------------------------------------;
  831.  
  832.         MOV    AX,DS:[002CH]    ;GET SEGMENT OF    ENVIORNMENT
  833.         MOV    ES,AX        ;PUT IT    INTO ES
  834.         MOV    AH,49H        ;RELEASE ALLOCATED MEMORY
  835.         INT    21H
  836.         MOV    DX,BUFF_END    ;LEAVE THIS MUCH RESIDENT
  837.         INT    27H        ;TEMINATE AND STAY RESIDENT
  838. ;---------------------------------------------------------;
  839. ; GET_PARAM RETRIEVES AN INTEGER FROM THE COMMAND LINE.      ;
  840. ;---------------------------------------------------------;
  841. GET_PARAM:    XOR    AX,AX        ;CLEAR AX FOR TOTAL
  842. GET_DIGIT:    MOV    BL,[SI]        ;GET CHARACTER INTO BL
  843.         CMP    BL,0DH        ;IS IT THE LAST    ONE?
  844.         JE    DONE
  845.         INC    SI        ;POINT TO NEXT CHARACTER
  846.         CMP    BL,","        ;IS IT THE DELIMITER?
  847.         JE    DONE
  848.         SUB    BL,30H        ;CONVERT ASCII TO INTEGER
  849.         JC    GET_DIGIT    ;IS IT A VALID DIGIT
  850.         CMP    BL,9
  851.         JA    GET_DIGIT    ;IF NOT    VALID, JUST SKIP IT
  852.         MOV    BH,10        ;TIMES 10 FOR NEXT DIGIT
  853.         MUL    BH        ;MULTIPLY SUM AND ADD THIS DIGIT
  854.         ADD    AL,BL        ;ADD DIGIT TO SUM
  855.         JMP    GET_DIGIT    ;READ ALL CHARACTERS ON    LINE
  856. DONE:        RET
  857. CSEG        ENDS
  858.         END    START
  859.